package com.carey.blog.framework.latke.repository.gae;

import java.util.ConcurrentModificationException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.carey.blog.framework.latke.repository.Transaction;

/**
 * Google App Engine datastore transaction. Just wraps
 * {@link com.google.appengine.api.datastore.Transaction} simply.
 * 
 */
public final class GAETransaction implements Transaction {

	/**
	 * Logger.
	 */
	private static final Logger LOGGER = Logger.getLogger(GAETransaction.class
			.getName());
	/**
	 * Underlying Google App Engine transaction.
	 */
	private com.google.appengine.api.datastore.Transaction appEngineDatastoreTx;
	/**
	 * Times of commit retries.
	 */
	public static final int COMMIT_RETRIES = 3;

	/**
	 * Constructs a {@link GAETransaction} object with the specified Google App
	 * Engine datastore {@link com.google.appengine.api.datastore.Transaction
	 * transaction}.
	 * 
	 * @param appEngineDatastoreTx
	 *            the specified Google App Engine datastore transaction
	 */
	public GAETransaction(
			final com.google.appengine.api.datastore.Transaction appEngineDatastoreTx) {
		this.appEngineDatastoreTx = appEngineDatastoreTx;
	}

	/**
	 * Commits this transaction with {@value #COMMIT_RETRIES} times of retries.
	 * 
	 * <p>
	 * <b>Throws</b>:<br/>
	 * {@link java.util.ConcurrentModificationException} - if commits failed
	 * </p>
	 * 
	 * @see #COMMIT_RETRIES
	 */
	@Override
	public void commit() {
		int retries = COMMIT_RETRIES;

		while (true) {
			try {
				appEngineDatastoreTx.commit();
				break;
			} catch (final ConcurrentModificationException e) {
				if (retries == 0) {
					throw e;
				}

				--retries;
				LOGGER.log(Level.WARNING,
						"Retrying to commit this transaction[id={0}, app={1}]",
						new Object[] { appEngineDatastoreTx.getId(),
								appEngineDatastoreTx.getApp() });
			}
		}
	}

	@Override
	public void rollback() {
		appEngineDatastoreTx.rollback();
	}

	@Override
	public boolean isActive() {
		return appEngineDatastoreTx.isActive();
	}
}
